package com.codi.bus.core.fund.service.impl;

import com.codi.base.util.DateUtil;
import com.codi.base.util.EqualsUtil;
import com.codi.base.util.MD5;
import com.codi.bus.constant.FundConst;
import com.codi.bus.core.domain.User;
import com.codi.bus.core.fund.FundErrorConst;
import com.codi.bus.core.fund.dao.FundDividendChangeDao;
import com.codi.bus.core.fund.domain.FundDividendChange;
import com.codi.bus.core.fund.dto.FundDividendChangeQueryDto;
import com.codi.bus.core.fund.dto.FundDividendDto;
import com.codi.bus.core.fund.enums.DividendAutoBuyEnum;
import com.codi.bus.core.fund.enums.FundDividendChangeStatusEnum;
import com.codi.bus.core.fund.request.DividendChangeRequestDto;
import com.codi.bus.core.fund.request.MyDividendHistoryRequestDto;
import com.codi.bus.core.fund.response.DividendChangeResult;
import com.codi.bus.core.fund.response.MyDividendHistoryQueryResult;
import com.codi.bus.core.fund.service.FundDividendService;
import com.codi.bus.core.service.FundDetailService;
import com.codi.bus.core.service.QueryService;
import com.codi.bus.core.service.UserService;
import com.codi.bus.core.service.WorkingDateService;
import com.codi.bus.core.service.model.ShareTypeModel;
import com.codi.bus.core.util.DesensitizeUtil;
import com.codi.fcloud.ufx.HsUtil;
import com.codi.fcloud.ufx.constant.HsConst;
import com.codi.fcloud.ufx.hssale.query.DividendsQuery;
import com.codi.fundData.domain.FundDetail;
import com.codi.fundData.domain.SecurityProduct;
import com.codi.message.constant.ErrorConst;
import com.codi.message.constant.ErrorConstant;
import com.codi.message.util.MessageUtil;
import com.codi.trade.dto.HsDividendMethodTradeRequestDto;
import com.codi.trade.dto.HsDividendQryDto;
import com.codi.trade.response.HsDividendMethodTradeResponse;
import com.codi.trade.response.HsFundDividendQryResponse;
import com.codi.trade.service.HsDividendMethodTradeService;
import com.github.pagehelper.PageHelper;
import com.google.common.base.Preconditions;
import com.google.common.base.Strings;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * 模块名
 *
 * @author spy
 * @version 1.0 2018-01-25
 * @since 1.0
 */
@Slf4j
@Service
public class FundDividendServiceImpl implements FundDividendService {

    @Autowired
    private DividendsQuery dividendsQuery;

    @Autowired
    private HsDividendMethodTradeService hsDividendMethodTradeService;

    @Autowired
    private UserService userService;

    @Autowired
    private FundDetailService fundDetailService;

    @Autowired
    private QueryService queryService;

    @Autowired
    private FundDividendChangeDao fundDividendChangeDao;

    @Autowired
    private WorkingDateService workingDateService;

    @Override
    public MyDividendHistoryQueryResult queryMyDividendHistory(MyDividendHistoryRequestDto dto) {
        MyDividendHistoryQueryResult result = new MyDividendHistoryQueryResult();

        result.setSuccess(false);

        Preconditions.checkNotNull(dto.getUserId());
//        Preconditions.checkNotNull(dto.getFundCode());
//        Preconditions.checkNotNull(dto.getTradeAcco());


        SecurityProduct product = null;
        if (!Strings.isNullOrEmpty(dto.getFundCode())) {
            product = fundDetailService.getSecurityProduct(dto.getFundCode());
        }
//        if (product == null) {
//            result.setErrorCode(ErrorConst.FUND_NOT_EXIST);
//            result.setErrorMessage(MessageUtil.getErrorMsg(ErrorConst.FUND_NOT_EXIST));
//            return result;
//        }

        int page = dto.getPage() == null ? 1 : dto.getPage();
        int size = dto.getSize() > 50 ? 50 : dto.getSize();

        Integer beginRowNum = (page - 1) * size + 1;

        User user = userService.getUser(dto.getUserId());


        HsDividendQryDto queryDto = HsDividendQryDto.builder()
                                                    .trade_acco(dto.getTradeAcco())
                                                    .client_id(user.getExternalClientId())
                                                    .fund_code(dto.getFundCode())
                                                    .qry_beginrownum(beginRowNum)
                                                    .request_num(size)
                                                    .sort_direction(HsConst.SORT_DIRECTION_DESC)
                                                    .build();

        List<HsFundDividendQryResponse> hsFundDividendQryResponses = dividendsQuery.query(queryDto);

        if (hsFundDividendQryResponses != null && !hsFundDividendQryResponses.isEmpty()) {

            log.debug("[userId={},fundCode={},分红数={}]", dto.getUserId(), dto.getFundCode(), hsFundDividendQryResponses.size());
            List<FundDividendDto> history = new ArrayList<>(hsFundDividendQryResponses.size());

            for (HsFundDividendQryResponse item : hsFundDividendQryResponses) {

                if (Strings.isNullOrEmpty(item.getRowcount())) {
                    log.info("rowcount is null, pass");
                    continue;
                }

                FundDividendDto fundDividendDto = FundDividendDto.builder()
                                                                 .fundCode(item.getFund_code())
                                                                 .affirmDate(HsUtil.parseDate8(item.getAffirm_date()))
                                                                 .dividendDate(HsUtil.parseDate8(item.getDividend_date()))

                                                                 .regShare(HsUtil.parseNumber(item.getReg_share()))
                                                                 .dividendShare(HsUtil.parseNumber(item.getDividend_share()))
                                                                 .netValue(HsUtil.parseNumber(item.getNet_value()))

                                                                 .autoBuy(item.getAuto_buy())
                                                                 .bankNo(item.getBank_no())
                                                                 .bankAccount(DesensitizeUtil.parseBankAcco(item.getBank_account()))
                                                                 .capitalMode(item.getCapital_mode())
                                                                 .build();
                if (product != null) {
                    fundDividendDto.setFundName(product.getSecuAbbr());
                }

                history.add(fundDividendDto);
            }
            result.setHistory(history);
        }
        result.setSuccess(true);

        return result;
    }

    @Override
    @Transactional
    public DividendChangeResult change(DividendChangeRequestDto dto) {

        DividendChangeResult result = new DividendChangeResult();
        result.setSuccess(false);

        // validate
        if (!DividendAutoBuyEnum.has(dto.getAutoBuy())) {
            result.setErrorCode(FundErrorConst.DIVIDEND_TYPE_ERROR);
            result.setErrorMessage(MessageUtil.getErrorMsg(FundErrorConst.DIVIDEND_TYPE_ERROR));
            return result;
        }

        String taAcco = dto.getTaAcco();
        if (taAcco.startsWith("*")) {
            taAcco = taAcco.substring(1);
        }

        // concurrency
        FundDetail fundDetail = fundDetailService.getFundDetail(dto.getFundCode());

        if (fundDetail == null) {
            result.setErrorCode(ErrorConst.FUND_NOT_EXIST);
            result.setErrorMessage(MessageUtil.getErrorMsg(ErrorConst.FUND_NOT_EXIST));
            return result;
        }

        if (EqualsUtil.equals(FundConst.FUND_TYPE_CODE_CURRENCY, fundDetail.getFundTypeCode().intValue())) {
            result.setErrorCode(FundErrorConst.CURRENCY_CAN_NOT_CHANGE_DIVIDEND_TYPE);
            result.setErrorMessage(MessageUtil.getErrorMsg(FundErrorConst.CURRENCY_CAN_NOT_CHANGE_DIVIDEND_TYPE));
            return result;
        }


        //change once
        final String taAccos = taAcco;
        Long changeCount = PageHelper.count(() -> {
            FundDividendChangeQueryDto record = FundDividendChangeQueryDto.builder()
                                                                          .userId(dto.getUserId())
                                                                          .tradeAcco(dto.getTradeAcco())
                                                                          .taAcco(taAccos)
                                                                          .fundCode(dto.getFundCode())
                                                                          .bizType(dto.getBizType())
                                                                          .createDate(new Date())
                                                                          .createDateFormat("%Y%m%d")
                                                                          .build();
            fundDividendChangeDao.select(record);
        });

        if (changeCount > 0) {
            result.setErrorCode(FundErrorConst.DIVIDEND_CHANGE_ONCE_PER_DAY);
            result.setErrorMessage(MessageUtil.getErrorMsg(FundErrorConst.DIVIDEND_CHANGE_ONCE_PER_DAY));
            return result;
        }

        // check applying date
        Date workingDay = workingDateService.getWorkingDay(new Date());

        if (workingDay != null) {
            Long applyingCount = PageHelper.count(() -> {
                FundDividendChangeQueryDto record = FundDividendChangeQueryDto.builder()
                                                                              .userId(dto.getUserId())
                                                                              .tradeAcco(dto.getTradeAcco())
                                                                              .taAcco(taAccos)
                                                                              .fundCode(dto.getFundCode())
                                                                              .bizType(dto.getBizType())
                                                                              .applyDate(workingDay)
                                                                              .build();
                fundDividendChangeDao.select(record);
            });

            if (applyingCount > 0) {
                result.setErrorCode(FundErrorConst.DIVIDEND_CHANGE_HAS_EXIST);
                result.setErrorMessage(MessageUtil.getErrorMsg(FundErrorConst.DIVIDEND_CHANGE_HAS_EXIST));
                return result;
            }
        }

        // share type
        ShareTypeModel shareTypeModel = queryService.getShareType(dto.getFundCode());

        if (shareTypeModel == null) {
            result.setErrorCode(FundErrorConst.SHARE_TYPE_NOT_FOUND);
            result.setErrorMessage(MessageUtil.getErrorMsg(FundErrorConst.SHARE_TYPE_NOT_FOUND));
            return result;
        }

        // change
        HsDividendMethodTradeRequestDto changeDto = HsDividendMethodTradeRequestDto.builder()
                                                                                   .ta_acco(taAcco)
                                                                                   .trade_acco(dto.getTradeAcco())
                                                                                   .password(MD5.MD5Encode(dto.getPassword()))
                                                                                   .fund_code(dto.getFundCode())
                                                                                   .share_type(shareTypeModel.getShareType())
                                                                                   .auto_buy(dto.getAutoBuy())
                                                                                   .build();

        HsDividendMethodTradeResponse response = hsDividendMethodTradeService.change(changeDto);


        if (response.getSuccess()) {
            result.setAutoBuy(dto.getAutoBuy());
            result.setAllotNo(response.getAllot_no());

            Date applyDate = null;
            if (!Strings.isNullOrEmpty(response.getApply_date())) {
                applyDate = DateUtil.parse(response.getApply_date(), "yyyyMMdd");
                String applyDateStr = DateUtil.format(applyDate, DateUtil.YYYYMMDD);
                result.setApplyDate(applyDateStr);
            }

            // add dividend change
            FundDividendChange record = FundDividendChange.builder()
                                                          .userId(dto.getUserId())
                                                          .tradeAcco(dto.getTradeAcco())
                                                          .taAcco(taAcco)
                                                          .fundCode(dto.getFundCode())
                                                          .shareType(shareTypeModel.getShareType())
                                                          .bizType(dto.getBizType())
                                                          .autoBuy(dto.getAutoBuy())
                                                          .allotNo(response.getAllot_no())
                                                          .status(FundDividendChangeStatusEnum.APPLY_SUC.getKey())
                                                          .createDate(new Date())
                                                          .applyDate(applyDate)
                                                          .build();

            fundDividendChangeDao.insertSelective(record);

        } else {
            log.warn("request hundsun error,errorCode={},errorMsg={}", response.getErrorCode(), response.getErrorMessage());
            result.setErrorCode(ErrorConstant.ERROR_HUNDSUNAPI_WRONG);

            String errorMsg = response.getErrorMessage();

            if (errorMsg != null && errorMsg.contains("请输入正确的密码")) {
                errorMsg = MessageUtil.getErrorMsg(FundErrorConst.TRADE_PWD_WRONG);
            }
            result.setErrorMessage(errorMsg);

            return result;
        }

        result.setSuccess(true);
        return result;
    }

}
